# Copyright (c) 2019 Presto Labs Pte. Ltd.
# Author: leon

import ujson as json
import functools
import logging

from coin.base.timestamp import get_timestamp
from coin.base.book.types import TradeSide, create_market_trade_event
from coin.exchange.base.ws.handler import WebsocketHandler
from coin.exchange.uniswap_v3.kr_rest.product import UniswapProduct
from coin.exchange.uniswap_v3.book_builder import BookBuilder


@functools.lru_cache(maxsize=64)
def get_product_from_symbol(symbol):
  native_symbol = symbol
  return UniswapProduct.FromStrNativeProduct(native_symbol)


def _to_trade_side(side):
  if side == 'B':
    return TradeSide.TRADE_BUY_SIDE
  elif side == 'S':
    return TradeSide.TRADE_SELL_SIDE
  else:
    raise ValueError(side)


class UniswapHandler(WebsocketHandler):
  def on_book(self, record, queue_data, topic_data):
    message = record.data
    if not isinstance(message, dict):
      message = json.loads(message)
    if 'topic' in message and 'worker_id' in message:
      # forward_delay = get_timestamp() - message['timestamp']
      # logging.info(f'forward delay: {forward_delay}')
      message = json.loads(message['data'])
    symbol = message['symbol']
    product = get_product_from_symbol(symbol)
    native_symbol = product.native_symbol
    if not self.is_subscribed('book', native_symbol):
      return

    book = BookBuilder(native_symbol, book_builder_observer=self._book_builder_observer)
    book.bbo(message)
    self._books[native_symbol] = book
    self.ready = True

    book.update_timestamp(record.timestamp)
    book.update_topic_id(record.topic_id)
    if self._feed_checker:
      self._feed_checker.on_book(product=product, book=book, timestamp=record.timestamp)
    self.publish_event('book', native_symbol, book)

  def on_trade(self, record, queue_data, topic_data):
    message = record.data
    if not isinstance(message, dict):
      message = json.loads(message)

    symbol = message['symbol']
    product = get_product_from_symbol(symbol)
    native_symbol = product.native_symbol
    if not self.is_subscribed('trade', native_symbol):
      return

    for trade in message['trades']:
      price = trade['price']
      qty = trade['qty']
      side = _to_trade_side(trade['side'])
      trade_event = create_market_trade_event(record.timestamp,
                                              native_symbol,
                                              price,
                                              qty,
                                              side,
                                              topic_id=record.topic_id)
      if self._feed_checker:
        self._feed_checker.on_trade(product=product,
                                    trade_event=trade_event,
                                    timestamp=record.timestamp)
      self.publish_event('trade', native_symbol, trade_event)
